<?php

/**
 * @file
 * An extended subclass for field handling that adds multiple field grouping.
 *
 * Fields that want multiple value grouping options in addition to basic
 * field and formatter handling can extend this class.
 */
class date_handler_field_multiple extends content_handler_field_multiple {

    function option_definition() {
        $options = parent::option_definition();
        $options['repeat'] = array(
            'contains' => array(
                'show_repeat_rule' => array('default' => ''),
            )
        );
        $options['multiple'] = array(
            'contains' => array(
                'group' => array('default' => TRUE),
                'multiple_number' => array('default' => ''),
                'multiple_from' => array('default' => ''),
                'multiple_to' => array('default' => ''),
            )
        );
        $options['fromto'] = array(
            'contains' => array(
                'fromto' => array('default' => 'both'),
            )
        );

        return $options;
    }

    /**
     * Provide 'group multiple values' option,
     * adapted to the needs of the Date module.
     */
    function options_form(&$form, &$form_state) {
        parent::options_form($form, $form_state);
        unset($form['multiple']);

        $field = $this->content_field;
        $options = $this->options;

        $form += date_formatter_settings($form_state, $field, $options, TRUE);
        $form['multiple']['#weight'] = 1;
        $form['multiple']['group'] = array(
            '#title' => t('Group multiple values'),
            '#type' => 'checkbox',
            '#default_value' => $options['multiple']['group'],
            '#description' => t('If unchecked, each item in the field will create a new row, which may appear to cause duplicates. This setting is not compatible with click-sorting in table displays.'),
        );
    }

    function pre_render(&$values) {

        // If there are no values to render (displaying a summary, or query returned no results),
        // or if this is not a grouped field, do nothing specific.
        if (isset($this->view->build_info['summary']) || empty($values) || !$this->defer_query) {
            return parent::pre_render($values);
        }
        $field = $this->content_field;
        $db_info = content_database_info($field);
        $options = $this->options;
        $this->view->date_info->date_handler_fields = date_handler_fields($this->view);

        // Build the list of vids to retrieve.
        // TODO: try fetching from cache_content first ??
        $vids = array();
        $this->field_values = array();
        foreach ($values as $result) {
            if (isset($result->{$this->field_alias})) {
                $vids[] = $result->{$this->field_alias};
            }
        }

        // List columns to retrieve.
        $alias = content_views_tablename($field);
        // Prefix aliases with '_' to avoid clashing with field columns names.
        $query_columns = array(
            'node.vid AS _vid',
            "$alias.delta as _delta",
            // nid is needed to generate the links for 'link to node' option.
            'node.nid AS _nid',
        );
        // The actual field columns.
        foreach ($db_info['columns'] as $column => $attributes) {
            $query_columns[] = "$alias.$attributes[column] AS $column";
            $query_fields[] = "$alias.$attributes[column]";
        }
        // Retrieve all values, we limit them in date_prepare_node(),
        // a function that is used both by the handler and by the
        // node theme to take advantage of formatter settings.
        $where = array('1');
        $query = 'SELECT ' . implode(', ', $query_columns) .
                ' FROM {' . $db_info['table'] . "} $alias" .
                " LEFT JOIN {node} node ON node.vid = $alias.vid" .
                " WHERE node.vid IN (" . implode(',', $vids) . ') AND ' . implode(' OR ', $where) .
                " ORDER BY node.nid ASC, $alias.delta ASC";
        $result = db_query($query);

        while ($item = db_fetch_array($result)) {
            // Clean up the $item from vid and delta. We keep nid for now.
            $vid = $item['_vid'];
            unset($item['_vid']);
            $delta = !empty($item['_delta']) ? $item['_delta'] : 0;
            $item['#delta'] = $item['_delta'];
            unset($item['_delta']);
            $this->field_values[$vid][$delta] = $item;
        }
    }

    function render($values) {

        // By this time $values is a pseudo node that will be passed
        // to the theme. Add view information to it.
        $values->date_info = !empty($this->view->date_info) ? $this->view->date_info : new stdClass();
        $values->date_info->date_handler_fields = date_handler_fields($this->view);

        // Add the formatter settings to the pseudo node.
        $values->date_info->formatter_settings = $this->options;
        $values->date_info->aliases = $this->aliases;

        // If this is not a grouped field, use content_handler_field::render().
        if (!$this->defer_query) {
            return parent::render($values);
        }

        $field = $this->content_field;
        $field_name = $field['field_name'];
        $options = $this->options;

        $vid = $values->{$this->field_alias};
        if (isset($this->field_values[$vid])) {
            // Build a pseudo-node from the retrieved values.
            $node = drupal_clone($values);
            // content_format and formatters will need a 'type'.
            $node->type = $values->{$this->aliases['type']};
            $node->nid = $values->{$this->aliases['nid']};
            $node->vid = $values->{$this->aliases['vid']};
            $items = $this->field_values[$vid];
            $node->$field_name = $items;

            // Some formatters need to behave differently depending on the build_mode
            // (for instance: preview), so we provide one.
            $node->build_mode = NODE_BUILD_NORMAL;

            // Render items.
            $formatter_name = $options['format'];
            if ($items && ($formatter = _content_get_formatter($formatter_name, $field['type']))) {
                $rendered = array();
                if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
                    // Single-value formatter.
                    foreach ($items as $item) {
                        $output = content_format($field, $item, $formatter_name, $node);
                        if (!empty($output)) {
                            $rendered[] = $this->render_link($output, (object) array('nid' => $this->aliases['nid']));
                        }
                    }
                } else {
                    // Multiple values formatter.
                    $output = content_format($field, $items, $formatter_name, $values);
                    if (!empty($output)) {
                        $rendered[] = $this->render_link($output, (object) array('nid' => $this->aliases['nid']));
                    }
                }

                if (count($rendered) > 1) {
                    // TODO: could we use generic field display ?
                    return theme('content_view_multiple_field', $rendered, $field, $values);
                } elseif ($rendered) {
                    return $rendered[0];
                }
            }
        }

        return '';
    }

}

